shared uniform extern float4x4 g_mViewProj:
    VIEWPROJECTION;
uniform extern float4x4 g_mWorld:
    WORLD;

uniform extern texture g_ReflectionTexture;
texture g_NoiseTexture;
float   g_fAmplitude;
float   g_fPhase;
float3  g_vCameraPosition;

float waveSpeed = 0.34000;
float noiseSpeed = 0.18000;
float fadeBias = 0.30000;
float fadeExp = 6.08000;
float4 waterColor = float4(0.1961, 0.3459, 0.6842, 1);

sampler3D NoiseTextureSampler =
sampler_state {
    Texture = <g_NoiseTexture>;
    MinFilter = Anisotropic;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
    AddressW = WRAP;
};

sampler ReflectionTexture = sampler_state {
    Texture = <g_ReflectionTexture>;
    MinFilter = ANISOTROPIC;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = MIRROR;
    AddressV = MIRROR;
};

struct VS_INPUT {
float3 Position  :
    POSITION;
float3 Normal    :
    NORMAL;
};

struct VS_OUTPUT {
float4 Position  :
    POSITION;
float3 Normal    :
    TEXCOORD0;
float3 Eye:
    TEXCOORD1;
float4 Texture:
    TEXCOORD2;
float3 Hede:
    TEXCOORD3;
float Alpha:
    FOG;
};

VS_OUTPUT VS_Plain(VS_INPUT input) {
    VS_OUTPUT output = (VS_OUTPUT)0;
    output.Alpha = 0.75f;

    output.Normal = mul(float4(input.Normal, 0.0f), g_mWorld).xyz;
    float4 pos = mul(float4(input.Position, 1.0f), g_mWorld);
    output.Position = mul(pos, g_mViewProj);
    output.Eye = g_vCameraPosition - pos;
    output.Texture = output.Position;
    output.Hede = input.Position.xzy;
    return output;
}

struct PS_OUTPUT {
float4 RGBColor :
    COLOR0;  // Pixel color
};

PS_OUTPUT PS_Plain(VS_OUTPUT input): COLOR0 {
    PS_OUTPUT Output = (PS_OUTPUT)0;

    float3 bumpTex = input.Hede;
    bumpTex.x += waveSpeed * g_fPhase;
    bumpTex.z += noiseSpeed * g_fPhase;
    float4 noisy = tex3D(NoiseTextureSampler, bumpTex);
    float3 bump = 2 * noisy - 1;
    bump.xz *= 0.15;
    bump.y = 0.8 * abs(bump.y) + 0.2;
    bump = normalize(input.Normal + bump);

    input.Texture += float4(bump.xzy, 0) * 2;
    float2 tex;
    tex.x = .5f * input.Texture.x / input.Texture.w + .5f;
    tex.y = -.5f * input.Texture.y / input.Texture.w + .5f;

    float4 refl = tex2D(ReflectionTexture, tex);

    float lrp = 1 - dot(-normalize(input.Eye), bump);

    // Interpolate between the water color and reflection
    Output.RGBColor = lerp(waterColor, refl, saturate(fadeBias + pow(lrp, fadeExp)));
    Output.RGBColor.a *= input.Alpha;

    return Output;
}

technique RenderWater {
    pass P1
    {
        VertexShader = compile vs_3_0 VS_Plain();
        PixelShader = compile ps_3_0 PS_Plain();
    }
}
